package customer

import (
	"context"
	"fmt"
	"github.com/360EntSecGroup-Skylar/excelize"
	"github.com/google/wire"
	"go.manyji.com/lib/util/convert"
	"reflect"
	"sieve_admin_server/app/dao"
	"sieve_admin_server/app/dao/income"
	"sieve_admin_server/app/schema"
	serviceUtil "sieve_admin_server/app/service/util"
	"sieve_admin_server/pkg/util"
	pkgUtil "sieve_admin_server/pkg/util"
	"strings"
	"time"
)

var (
	InComeSet = wire.NewSet(wire.Struct(new(InComeSrv), "*"))
)

type InComeSrv struct {
	UserSrv              *UserSrv
	IncomeStatisticsRepo *dao.IncomeStatisticsRepo
}

func (a *InComeSrv) Query(ctx context.Context, uid uint64, reqArgs map[string]interface{}, p schema.PaginationParam) interface{} {

	var (
		entity  = income.IncomeStatistics{}
		cusSQL  string
		repKeys = util.Struct2Slice(entity, "json", entity.TableName())
	)

	var isAdminRole bool
	_, err := a.UserSrv.GetUserInfo(context.Background(), uid, &isAdminRole)
	if err != nil {
		return err
	}

	if _, ok := reqArgs["date"]; ok {
		queryDates := strings.Split(reqArgs["date"].(string), ",")

		if len(queryDates) == 2 {
			cusSQL = fmt.Sprintf("date >= '%v' AND date <= '%v'", queryDates[0], queryDates[1])
			ctx = context.WithValue(ctx,
				"condition_customized", cusSQL,
			)
			delete(reqArgs, "date")
		}
	}

	// 管理员账号不需要额外的连表查询
	if !isAdminRole {
		var (
			joinString = fmt.Sprintf(
				"INNER JOIN user ON "+
					"income_statistics.account_id = user.id AND (user.id = %v"+
					" OR user.leader_id = %v "+
					" OR user.top_leader_id = %v)", uid, uid, uid)
		)

		ctx = context.WithValue(
			context.WithValue(ctx, "join", joinString),
			"group_by", "id")
	}

	req, err := a.IncomeStatisticsRepo.Query(ctx, reqArgs, p, repKeys)
	if err != nil {
		return err
	}

	if req != nil {

		var (
			t = income.IncomeStatistics{}
		)
		for _, v := range req.(map[string]interface{})["list"].([]interface{}) {

			respIS := v.(*income.IncomeStatistics)
			t.PointsConsume += respIS.PointsConsume
			t.PointsConsumeAccount += respIS.PointsConsumeAccount
			t.PointsConsumeGift += respIS.PointsConsumeGift
			t.TaskNums += respIS.TaskNums
			t.TaskNumsValid += respIS.TaskNumsValid
			t.Profit += respIS.Profit
		}

		req.(map[string]interface{})["all"] = map[string]interface{}{
			"points_consume":         t.PointsConsume,
			"points_consume_account": t.PointsConsumeAccount,
			"points_consume_gift":    t.PointsConsumeGift,
			"task_nums":              t.TaskNums,
			"task_nums_valid":        t.TaskNumsValid,
			"profit":                 t.Profit,
		}
	}
	return req
}

func (a *InComeSrv) Export(ctx context.Context, uid uint64, reqArgs map[string]interface{}) interface{} {

	var (
		p = schema.PaginationParam{
			OnlyData: true,
		}
		queryArgs = map[string]interface{}{
			"id": func() string {
				ids := reqArgs["ids"].(string)
				return fmt.Sprintf("(%v)", strings.Join(strings.Split(ids, "|"), ","))
			}(),
		}
	)

	ctx = context.WithValue(ctx,
		"condition", map[string]string{"id": "IN"},
	)

	req := a.Query(ctx, uid, queryArgs, p)
	if req != nil {
		if _, ok := req.(error); ok && req != nil {
			return req
		}
	}

	selectedItems := []string{
		"date",
		"business_type_desc",
		"points_consume",
		"points_consume_account",
		"points_consume_gift",
		"profit",
		"task_nums",
		"task_nums_valid",
		"leader_name",
	}
	req = a.export(ctx, req, strings.Join(selectedItems, "|"))
	if req != nil {
		if _, ok := req.(error); ok {
			return req
		}
	}

	return req
}

func (a *InComeSrv) export(ctx context.Context, req interface{}, selectedItems string) interface{} {

	var (
		selectedItemMap = make(map[string]int)
		xlsx            = excelize.NewFile()
		categories      = map[string]string{"A1": "日期", "B1": "业务类型", "C1": "消耗积分", "D1": "账户消耗", "E1": "赠送消耗", "F1": "利润", "G1": "任务数", "H1": "有效数", "I1": "操作人"}
		colWidths       = map[string]float64{"A": 18, "B": 20, "C": 20, "D": 20, "E": 20, "F": 20, "G": 12, "H": 12, "I": 15}
	)

	for key, value := range categories {
		xlsx.SetCellValue("Sheet1", key, value)
		_style, err := xlsx.NewStyle(`{"fill":{"type":"pattern","color":["#EEECE1"],"pattern":1},"alignment":{"horizontal":"center","vertical":"center"},"font":{"bold":true,"family":"宋体","size":10}}`)
		if err == nil {
			xlsx.SetCellStyle("Sheet1", key, key, _style)
		}
	}

	for k, v := range colWidths {
		xlsx.SetColWidth("Sheet1", k, k, v)
	}

	for i, v := range strings.Split(fmt.Sprintf("%v", selectedItems), "|") {
		selectedItemMap[v] = i
	}

	p := map[string]struct{}{
		"points_consume":         {},
		"points_consume_account": {},
		"points_consume_gift":    {},
		"profit":                 {},
	}

	v := req.(map[string]interface{})
	for index, vv := range v["list"].([]interface{}) {

		var (
			columIndex  = 'A'
			columOffset = 1
		)
		for kkk, vvv := range util.Struct2Map(vv, "json") {

			if len(selectedItemMap) > 0 {
				if i, ok := selectedItemMap[kkk]; !ok {
					continue
				} else {
					columOffset = i
				}
			}

			cell := fmt.Sprintf("%c", int(columIndex)+columOffset) + convert.ToString(index+2)

			if reflect.TypeOf(vvv).Kind() == reflect.Ptr {
				vOf := reflect.ValueOf(vvv)
				if vOf.IsNil() {
					vvv = ""
				} else {
					vvv = vOf.Elem()
				}
			}

			if _, ok := p[kkk]; ok {
				vvv = pkgUtil.Decimal(float64(vvv.(uint64))/10000.0, 5)
			}
			xlsx.SetCellValue("Sheet1", cell, vvv)
		}
		xlsx.SetRowHeight("Sheet1", index+2, 18)
	}

	xlsx.SetSheetName("Sheet1", "第一页")

	filPath, fileName := a.getExportPath(convert.ToString(time.Now().UnixMilli())+".csv", 1)
	err := xlsx.SaveAs(filPath)
	if err != nil {
		return err
	}

	req = fileName

	return req
}

func (a *InComeSrv) getExportPath(fileName string, bizTy int) (string, string) {

	var (
		bizTyMap = map[int]string{
			1: "income",
		}
	)

	relativePath := fmt.Sprintf("%v/export/%v", bizTyMap[bizTy], fileName)

	return serviceUtil.GetFilePath(
		fmt.Sprintf("%v/%v",
			serviceUtil.FileStorage(),
			relativePath),
	), relativePath
}
